/***************************************************************************
 *   This file is part of Colorbar.                                        *
 *   Copyright (C) 2009 Pim Schellart <P.Schellart@science.ru.nl>          *
 *   Copyright (C) 2009 Wilbert van Ham <W.vanHam@astro.ru.nl>             *
 *                                                                         *
 *   Colorbar is free software: you can redistribute it and/or modify      *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation, either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   Colorbar is distributed in the hope that it will be useful,           *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with Colorbar.  If not, see <http://www.gnu.org/licenses/>.     *
 ***************************************************************************/

#include <QPainter>
#include <QtPlugin>
#include "colorbar.h"

Q_EXPORT_PLUGIN2(colorbar, Colorbar);

Colorbar::Colorbar()
{
	setObjectName("Colorbar");
    _outerL=0;
    _outerR=65536;

    _innerCenter=0.0;
    _innerWidth=1.0;
    
    _colorMap.append(Qt::white);
    _colorMap.append(Qt::black);
}

Colorbar::Colorbar(int outerL, int outerR, double innerCenter, double innerWidth)
{
    _outerL=outerL;
    _outerR=outerR;

    _innerCenter=innerCenter;
    _innerWidth=innerWidth;

    _colorMap.append(Qt::white);
    _colorMap.append(Qt::black);
}

void Colorbar::onInitialize(QObject *manager)
{
	// sends gray changes
	connect(this, SIGNAL(innerGrayChanged(double, double)), manager, SIGNAL(grayChanged(double, double)));
	//listens to gray changes
	connect(manager, SIGNAL(grayChanged(double, double)), this, SLOT(setInnerGray(double, double)));
	//listens to colormap changes
	connect(manager, SIGNAL(colormapChanged(QVector<QColor>)), this, SLOT(setColorMap(QVector<QColor>)));
}

void Colorbar::paintEvent(QPaintEvent *event)
{
    // Set painter for widget
    QPainter painter(this);

    // Define logical coordinate system
    painter.setWindow(Colorbar::WINDOW_START_X,Colorbar::WINDOW_START_Y,Colorbar::WINDOW_WIDTH,Colorbar::WINDOW_HEIGHT);

    // Store viewport and window to allow coordinate transformations
    _viewport=painter.viewport();
    _window=painter.window();

    // Setup gradient to run from -(width+0.5) to (width+0.5) in logical coordinates
    // so inner range can be dragged entirely of screen in both directions.
    QLinearGradient gradient(Colorbar::WINDOW_START_X-fabs(_innerWidth)*Colorbar::WINDOW_WIDTH,
                             Colorbar::GRADIENT_START_Y,
                             Colorbar::WINDOW_WIDTH+fabs(_innerWidth)*Colorbar::WINDOW_WIDTH,
                             Colorbar::GRADIENT_END_Y);

    // Set colors on gradient
    double step=_innerWidth/(_colorMap.size()-1);
    for (int i=0; i<_colorMap.size(); ++i)
    {
        gradient.setColorAt(normalize(_innerCenter-_innerWidth/2+i*step),_colorMap[i]);
    }

    // Allow for mirroring of colors in case _innerWidth is negative
    if (_innerWidth>=0)
    {
        gradient.setColorAt(0.0, _colorMap[0]);
        gradient.setColorAt(1.0, _colorMap[_colorMap.size()-1]);
    }
    else
    {
        gradient.setColorAt(1.0, _colorMap[0]);
        gradient.setColorAt(0.0, _colorMap[_colorMap.size()-1]);
    }

    // Draw rectangle with gradient on widget
    painter.setBrush(gradient);
    painter.drawRect(Colorbar::WINDOW_START_X,Colorbar::WINDOW_START_Y,Colorbar::WINDOW_WIDTH,Colorbar::COLORBAR_HEIGHT);

    // Draw line with ticks underneath widget
    // outer range is divided into 10 steps and corresponding values are displayed beneath each tick.
    painter.drawLine(Colorbar::WINDOW_START_X,Colorbar::COLORBAR_HEIGHT,Colorbar::WINDOW_WIDTH,Colorbar::COLORBAR_HEIGHT);
    painter.setBrush(QBrush(Qt::black, Qt::SolidPattern));
    for (int i=0; i<=Colorbar::WINDOW_WIDTH; ++i)
    {
        if (i % 100 == 0)
        {
            painter.drawLine(i,Colorbar::MAJOR_TICK_START,i,Colorbar::MAJOR_TICK_END);
            painter.drawText(i+Colorbar::TEXT_START_X,Colorbar::TEXT_START_Y,Colorbar::TEXT_WIDTH,Colorbar::TEXT_HEIGHT,Qt::AlignCenter | Qt::KeepAspectRatio,QString::number(valueFromCoordinate(i)));
        }
    }
}

void Colorbar::mousePressEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton && event->modifiers() & Qt::ControlModifier)
    {
        double point=normFromAbsoluteCoordinates(event->pos());
        if (point<=0.5 && point>=0.0)
        {
            setInnerWidth(2*(0.5-point));
        }
        else if (point>0.5 && point<=1.0)
        {
            setInnerWidth(-2*(point-0.5));
        }
    }
    else if (event->buttons() & Qt::LeftButton)
    {
        double point=normFromAbsoluteCoordinates(event->pos());
        if (point>=-fabs(_innerWidth)/2 && point<=1.0+(fabs(_innerWidth)/2))
        {
            setInnerCenter(point-0.5);
        }
    }
	emit innerGrayChanged(_innerCenter+.5, -1./_innerWidth);
}

void Colorbar::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton && event->modifiers() & Qt::ControlModifier)
    {
        double point=normFromAbsoluteCoordinates(event->pos());
        if (point<=0.5 && point>=0.0)
        {
            setInnerWidth(2*(0.5-point));
        }
        else if (point>0.5 && point<=1.0)
        {
            setInnerWidth(-2*(point-0.5));
        }
    }
    else if (event->buttons() & Qt::LeftButton)
    {
        double point=normFromAbsoluteCoordinates(event->pos());
        if (point>=-fabs(_innerWidth)/2 && point<=1.0+(fabs(_innerWidth)/2))
        {
            setInnerCenter(point-0.5);
        }
    }
	emit innerGrayChanged(_innerCenter+.5, -1./_innerWidth);
}

double Colorbar::normalize(double point)
{
    double totalWidth=2*fabs(_innerWidth)+1.0;
    return (point+fabs(_innerWidth)+0.5)/totalWidth;
}

double Colorbar::normFromAbsoluteCoordinates(QPoint point)
{
    double viewsize=static_cast<double>(_viewport.right()-_viewport.left()+1);
    return point.x()/viewsize;
}

QSize Colorbar::sizeHint() const
{
    QSize size(1000,100);
    return size;
}
